#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ESP32控制盒综合测试程序
整合继电器控制、日志获取、统计信息、自动化测试等功能
支持MQTT协议通信，提供完整的设备测试解决方案
"""

import paho.mqtt.client as mqtt
import time
import sys
import json
import threading
from datetime import datetime
import random
import signal

class ControlBoxTester:
    def __init__(self, broker_host="mqtt.hhwl.lhb.ink", broker_port=1883, 
                 username="xxxxxxxxxxxx", password="controlv2", device_mac="3c8a1fd51e48"):
        """
        初始化控制盒测试客户端
        
        Args:
            broker_host: MQTT服务器地址
            broker_port: MQTT服务器端口
            username: MQTT用户名
            password: MQTT密码
            device_mac: 设备MAC地址
        """
        self.broker_host = broker_host
        self.broker_port = broker_port
        self.username = username
        self.password = password
        self.device_mac = device_mac
        
        # MQTT主题
        self.relay_publish_topic = f"/c/{device_mac}/get"        # 继电器控制
        self.relay_subscribe_topic = f"/c/{device_mac}/send"     # 继电器响应
        self.log_publish_topic = f"/c/{device_mac}/log/get"      # 日志命令
        self.log_subscribe_topic = f"/c/{device_mac}/log/send"   # 统计信息和日志数据（统一topic）
        
        # 初始化MQTT客户端
        self.client = mqtt.Client()
        self.client.username_pw_set(username, password)
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_disconnect = self.on_disconnect
        
        # 测试统计
        self.test_stats = {
            'total_commands': 0,
            'successful_commands': 0,
            'failed_commands': 0,
            'timeout_commands': 0,
            'start_time': None,
            'last_response_time': None,
            'protocol_errors': 0,
            'response_times': [],
            'relay_tests': {
                '读取状态': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
                '继电器开启': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
                '继电器关闭': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
                '全部开启': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
                '全部关闭': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
                '延时测试': {'total': 0, 'success': 0, 'failed': 0, 'timeout': 0},
            }
        }
        
        # 响应验证
        self.waiting_for_response = False
        self.response_received = False
        self.response_timeout = 10.0
        self.last_command_description = ""
        self.response_lock = threading.Lock()
        
        # 设备信息存储
        self.device_stats = {}
        self.device_logs = []
        self.device_relay_status = {'high': 0, 'low': 0}  # 继电器状态
        
        self.running = True
        
        print(f"🔧 ESP32控制盒综合测试器")
        print(f"📡 MQTT服务器: {broker_host}:{broker_port}")
        print(f"👤 用户名: {username}")
        print(f"🎯 设备MAC: {device_mac}")
        print(f"📤 继电器控制: {self.relay_publish_topic}")
        print(f"📥 继电器响应: {self.relay_subscribe_topic}")
        print(f"📤 日志控制: {self.log_publish_topic}")
        print(f"📥 统计和日志: {self.log_subscribe_topic} (统一topic)")
        print("-" * 80)

    def calculate_checksum(self, data):
        """计算校验和"""
        return sum(data) & 0xFF

    def create_protocol_packet(self, address=0x01, function_code=0x10, data1=0x00, data2=0x00, data3=0x00, data4=0x00):
        """创建8字节继电器控制协议数据包"""
        packet = [0x55, address, function_code, data1, data2, data3, data4, 0x00]
        packet[7] = self.calculate_checksum(packet[:7])
        return bytes(packet)

    def on_connect(self, client, userdata, flags, rc):
        """MQTT连接回调"""
        if rc == 0:
            print("✅ MQTT连接成功!")
            # 订阅所有相关主题
            client.subscribe(self.relay_subscribe_topic)
            client.subscribe(self.log_subscribe_topic)
            print(f"📥 已订阅继电器响应: {self.relay_subscribe_topic}")
            print(f"📥 已订阅统计和日志: {self.log_subscribe_topic}")
        else:
            print(f"❌ MQTT连接失败，错误码: {rc}")

    def on_message(self, client, userdata, msg):
        """MQTT消息接收回调"""
        topic = msg.topic
        
        if topic == self.relay_subscribe_topic:
            self.handle_relay_response(msg)
        elif topic == self.log_subscribe_topic:
            self.handle_stats_response(msg)
        else:
            print(f"📨 收到未知主题消息: {topic}")

    def handle_relay_response(self, msg):
        """处理继电器响应"""
        with self.response_lock:
            if self.waiting_for_response:
                self.response_received = True
                self.test_stats['last_response_time'] = datetime.now()
                
                print(f"📨 继电器响应 [{self.last_command_description}]:")
                print(f"   时间: {datetime.now().strftime('%H:%M:%S.%f')[:-3]}")
                print(f"   长度: {len(msg.payload)} 字节")
                
                if len(msg.payload) == 8:
                    data = list(msg.payload)
                    print(f"   数据: {' '.join([f'0x{b:02X}' for b in data])}")
                    
                    if data[0] == 0x22:  # 验证响应头
                        function_code = data[2]
                        relay_state1 = data[5]  # 高8位继电器状态
                        relay_state2 = data[6]  # 低8位继电器状态
                        
                        # 更新继电器状态
                        self.device_relay_status['high'] = relay_state1
                        self.device_relay_status['low'] = relay_state2
                        
                        print(f"   功能码: 0x{function_code:02X}")
                        print(f"   继电器状态: 高8位=0x{relay_state1:02X}({relay_state1:08b}) 低8位=0x{relay_state2:02X}({relay_state2:08b})")
                        
                        # 显示具体继电器状态
                        relay_status = []
                        for i in range(14, 8, -1):
                            if i <= 14:
                                state = "ON" if (relay_state1 & (1 << (i-9))) else "OFF"
                                relay_status.append(f"R{i}:{state}")
                        for i in range(8, 0, -1):
                            state = "ON" if (relay_state2 & (1 << (i-1))) else "OFF"
                            relay_status.append(f"R{i}:{state}")
                        
                        print(f"   继电器详情: {' '.join(relay_status)}")
                        print("   ✅ 继电器响应正确")
                    else:
                        print(f"   ⚠️  协议头错误，期望0x22，实际0x{data[0]:02X}")
                        self.test_stats['protocol_errors'] += 1
                else:
                    print(f"   ⚠️  数据长度异常: {len(msg.payload)}字节")
                    self.test_stats['protocol_errors'] += 1

    def handle_stats_response(self, msg):
        """处理统计信息和日志数据响应（统一topic）"""
        try:
            # 安全解码，处理无效UTF-8字符
            try:
                payload_str = msg.payload.decode('utf-8')
            except UnicodeDecodeError:
                payload_str = msg.payload.decode('utf-8', errors='replace')
                print(f"⚠️  响应数据包含无效UTF-8字符，已替换")
            
            response_data = json.loads(payload_str)
            
            # 检查是否为日志数据（包含logs字段）
            if 'logs' in response_data:
                self.handle_log_data(response_data, payload_str)
            else:
                # 处理统计信息
                self.handle_statistics_data(response_data, payload_str)
                
        except json.JSONDecodeError as e:
            try:
                payload_str = msg.payload.decode('utf-8', errors='replace')
            except:
                payload_str = str(msg.payload)
            print(f"📊 响应数据JSON解析失败: {e}")
            print(f"   原始数据长度: {len(msg.payload)}字节")
            print(f"   完整数据内容:")
            print(f"   {payload_str}")
            
        except Exception as e:
            print(f"📊 处理响应数据时出错: {e}")
            print(f"   完整错误信息: {str(e)}")
            import traceback
            print(f"   错误堆栈:")
            traceback.print_exc()

    def handle_statistics_data(self, stats_data, payload_str):
        """处理统计信息数据"""
        self.device_stats = stats_data
        
        print(f"📊 设备统计信息 (完整版):")
        print(f"   数据大小: {len(payload_str)} 字符")
        print("-" * 70)
        
        # 遍历并显示所有统计信息
        for key, value in stats_data.items():
            if isinstance(value, dict):
                print(f"   {key}:")
                for sub_key, sub_value in value.items():
                    if isinstance(sub_value, (list, dict)):
                        print(f"     {sub_key}: {sub_value}")
                    else:
                        print(f"     {sub_key}: {sub_value}")
            elif isinstance(value, list):
                print(f"   {key}: {value}")
            else:
                print(f"   {key}: {value}")
        
        print("-" * 70)
        
        # 额外的格式化显示重要信息
        print(f"📋 重要信息摘要:")
        print(f"   设备ID: {stats_data.get('device_id', 'N/A')}")
        print(f"   固件版本: {stats_data.get('Version', 'N/A')}")
        print(f"   设备编号: {stats_data.get('device_5id', 'N/A')}")
        print(f"   运行时间: {stats_data.get('uptime_seconds', 0)}秒 ({stats_data.get('uptime_seconds', 0)//3600}小时)")
        print(f"   重启次数: {stats_data.get('reboot_count', 0)}")
        print(f"   重启原因: {stats_data.get('last_reset_reason', 'N/A')}")
        print(f"   日志缓冲区: {stats_data.get('log_buffer_count', 0)}/{stats_data.get('log_buffer_size', 0)}")
        
        # 内存信息
        if 'free_heap' in stats_data:
            print(f"   空闲堆内存: {stats_data['free_heap']} 字节")
        if 'min_free_heap' in stats_data:
            print(f"   最小空闲堆: {stats_data['min_free_heap']} 字节")
        if 'total_heap' in stats_data:
            print(f"   总堆内存: {stats_data['total_heap']} 字节")
        
        # 网络信息
        if 'wifi_info' in stats_data:
            wifi_info = stats_data['wifi_info']
            print(f"   WiFi连接信息:")
            for wifi_key, wifi_value in wifi_info.items():
                print(f"     {wifi_key}: {wifi_value}")
        
        # 错误统计（完整显示）
        error_fields = ['wifi_errors', 'mqtt_errors', 'relay_errors', 'system_warnings', 
                       'ota_errors', 'nvs_errors', 'task_errors', 'memory_errors']
        
        print(f"   错误统计:")
        total_errors = 0
        for error_field in error_fields:
            if error_field in stats_data:
                error_count = stats_data[error_field]
                total_errors += error_count
                print(f"     {error_field}: {error_count}")
        
        # 显示所有其他数值统计
        numeric_fields = ['nvs_writes', 'ota_attempts', 'task_count', 'queue_size']
        print(f"   其他统计:")
        for field in numeric_fields:
            if field in stats_data:
                print(f"     {field}: {stats_data[field]}")
        
        if total_errors == 0:
            print(f"   ✅ 总错误数: 0 (设备运行正常)")
        else:
            print(f"   ⚠️  总错误数: {total_errors}")

    def handle_log_data(self, log_data, payload_str):
        """处理日志数据"""
        logs = log_data.get('logs', [])
        self.device_logs = logs
        
        print(f"📋 设备日志数据:")
        print(f"   设备ID: {log_data.get('device_id', 'N/A')}")
        print(f"   日志条数: {len(logs)}")
        print(f"   缓冲区状态: {log_data.get('buffer_logs', 0)}/{log_data.get('buffer_size', 0)}")
        print(f"   数据大小: {len(payload_str)} 字符")
        
        if logs:
            print(f"   完整日志列表:")
            for i, log in enumerate(logs):  # 显示所有日志
                msg_text = log.get('msg', '')  # 不限制显示长度
                # 确保日志文本是可打印的
                try:
                    msg_text.encode('utf-8')
                except UnicodeEncodeError:
                    msg_text = repr(msg_text)
                print(f"     {i+1:3d}. {msg_text}")
        else:
            print("   📝 暂无日志数据")

    def on_disconnect(self, client, userdata, rc):
        """MQTT断开连接回调"""
        print(f"🔌 MQTT连接断开，错误码: {rc}")

    def connect(self):
        """连接MQTT服务器"""
        try:
            print(f"🔄 正在连接MQTT服务器...")
            self.client.connect(self.broker_host, self.broker_port, 60)
            self.client.loop_start()
            time.sleep(3)  # 等待连接建立
            return True
        except Exception as e:
            print(f"❌ 连接失败: {e}")
            return False

    def disconnect(self):
        """断开MQTT连接"""
        self.client.loop_stop()
        self.client.disconnect()
        print("👋 已断开MQTT连接")

    def send_relay_command(self, packet, description="", test_type=""):
        """发送继电器控制命令"""
        with self.response_lock:
            self.waiting_for_response = True
            self.response_received = False
            self.last_command_description = description
        
        if test_type in self.test_stats['relay_tests']:
            self.test_stats['relay_tests'][test_type]['total'] += 1
        
        try:
            packet_hex = ' '.join([f'0x{b:02X}' for b in packet])
            print(f"\n📤 [{datetime.now().strftime('%H:%M:%S.%f')[:-3]}] {description}")
            print(f"   数据: {packet_hex}")
            
            self.test_stats['total_commands'] += 1
            
            result = self.client.publish(self.relay_publish_topic, packet)
            if result.rc != mqtt.MQTT_ERR_SUCCESS:
                print(f"   ❌ 发送失败，错误码: {result.rc}")
                self.test_stats['failed_commands'] += 1
                if test_type in self.test_stats['relay_tests']:
                    self.test_stats['relay_tests'][test_type]['failed'] += 1
                with self.response_lock:
                    self.waiting_for_response = False
                return False
            
            # 等待响应
            start_time = time.time()
            while time.time() - start_time < self.response_timeout:
                with self.response_lock:
                    if self.response_received:
                        response_time = (time.time() - start_time) * 1000
                        print(f"   ✅ 命令执行成功，响应时间: {response_time:.1f}ms")
                        self.test_stats['successful_commands'] += 1
                        self.test_stats['response_times'].append(response_time)
                        if test_type in self.test_stats['relay_tests']:
                            self.test_stats['relay_tests'][test_type]['success'] += 1
                        self.waiting_for_response = False
                        return True
                time.sleep(0.1)
            
            # 超时
            print(f"   ⏰ 响应超时 ({self.response_timeout}秒)")
            self.test_stats['timeout_commands'] += 1
            if test_type in self.test_stats['relay_tests']:
                self.test_stats['relay_tests'][test_type]['timeout'] += 1
            with self.response_lock:
                self.waiting_for_response = False
            return False
            
        except Exception as e:
            print(f"   ❌ 发送异常: {e}")
            self.test_stats['failed_commands'] += 1
            if test_type in self.test_stats['relay_tests']:
                self.test_stats['relay_tests'][test_type]['failed'] += 1
            with self.response_lock:
                self.waiting_for_response = False
            return False

    def send_log_command(self, command_dict, description=""):
        """发送日志控制命令"""
        try:
            command_json = json.dumps(command_dict)
            print(f"\n📤 {description}")
            print(f"   命令: {command_json}")
            
            result = self.client.publish(self.log_publish_topic, command_json)
            if result.rc == mqtt.MQTT_ERR_SUCCESS:
                print(f"   ✅ 命令发送成功")
                time.sleep(1)  # 等待响应
                return True
            else:
                print(f"   ❌ 命令发送失败，错误码: {result.rc}")
                return False
        except Exception as e:
            print(f"   ❌ 发送异常: {e}")
            return False

    # 继电器控制函数
    def read_relay_status(self):
        """读取继电器状态"""
        packet = self.create_protocol_packet(function_code=0x10)
        return self.send_relay_command(packet, "读取继电器状态", "读取状态")

    def open_relay(self, relay_num):
        """打开指定继电器"""
        if not (1 <= relay_num <= 14):
            print(f"❌ 继电器编号错误: {relay_num} (支持1-14)")
            return False
        packet = self.create_protocol_packet(function_code=0x12, data4=relay_num)
        return self.send_relay_command(packet, f"打开继电器{relay_num}", "继电器开启")

    def close_relay(self, relay_num):
        """关闭指定继电器"""
        if not (1 <= relay_num <= 14):
            print(f"❌ 继电器编号错误: {relay_num} (支持1-14)")
            return False
        packet = self.create_protocol_packet(function_code=0x11, data4=relay_num)
        return self.send_relay_command(packet, f"关闭继电器{relay_num}", "继电器关闭")

    def open_all_relays(self):
        """打开所有继电器"""
        packet = self.create_protocol_packet(function_code=0x13, data4=0xFF)
        return self.send_relay_command(packet, "打开所有继电器", "全部开启")

    def close_all_relays(self):
        """关闭所有继电器"""
        packet = self.create_protocol_packet(function_code=0x13, data4=0x00)
        return self.send_relay_command(packet, "关闭所有继电器", "全部关闭")

    def relay_open_delay(self, relay_num, delay_ms):
        """继电器打开延时关闭"""
        if not (1 <= relay_num <= 14):
            return False
        
        data1 = (delay_ms >> 16) & 0xFF
        data2 = (delay_ms >> 8) & 0xFF
        data3 = delay_ms & 0xFF
        
        packet = self.create_protocol_packet(function_code=0x21, data1=data1, data2=data2, data3=data3, data4=relay_num)
        return self.send_relay_command(packet, f"继电器{relay_num}开启{delay_ms}ms后关闭", "延时测试")

    def relay_close_delay(self, relay_num, delay_ms):
        """继电器关闭延时打开"""
        if not (1 <= relay_num <= 14):
            return False
        
        data1 = (delay_ms >> 16) & 0xFF
        data2 = (delay_ms >> 8) & 0xFF
        data3 = delay_ms & 0xFF
        
        packet = self.create_protocol_packet(function_code=0x22, data1=data1, data2=data2, data3=data3, data4=relay_num)
        return self.send_relay_command(packet, f"继电器{relay_num}关闭{delay_ms}ms后开启", "延时测试")

    # 日志和统计功能
    def get_device_stats(self):
        """获取设备统计信息"""
        return self.send_log_command({"cmd": "get_stats"}, "获取设备统计信息")

    def get_device_logs(self, count=50):
        """获取设备日志"""
        return self.send_log_command({"cmd": "get_logs", "count": count}, f"获取设备日志({count}条)")

    def clear_device_logs(self):
        """清空设备日志缓冲区"""
        return self.send_log_command({"cmd": "clear_logs"}, "清空设备日志缓冲区")

    def reset_device_stats(self):
        """重置设备统计信息"""
        return self.send_log_command({"cmd": "reset_stats"}, "重置设备统计信息")

    def reset_reboot_count(self):
        """重置重启次数"""
        return self.send_log_command({"cmd": "reset_reboot_count"}, "重置重启次数")

    def restart_device(self):
        """重启设备"""
        packet = self.create_protocol_packet(function_code=0x81)
        return self.send_relay_command(packet, "重启设备", "系统重启")

    def print_test_statistics(self):
        """打印测试统计信息"""
        if self.test_stats['start_time']:
            elapsed = (datetime.now() - self.test_stats['start_time']).total_seconds()
            rate = self.test_stats['total_commands'] / elapsed if elapsed > 0 else 0
            success_rate = (self.test_stats['successful_commands'] / self.test_stats['total_commands'] * 100) if self.test_stats['total_commands'] > 0 else 0
            
            print(f"\n" + "=" * 80)
            print(f"📊 测试统计报告 (运行时间: {elapsed:.1f}秒)")
            print("=" * 80)
            
            print(f"🎯 继电器控制统计:")
            print(f"   总命令数: {self.test_stats['total_commands']}")
            print(f"   成功: {self.test_stats['successful_commands']} ({success_rate:.1f}%)")
            print(f"   失败: {self.test_stats['failed_commands']}")
            print(f"   超时: {self.test_stats['timeout_commands']}")
            print(f"   协议错误: {self.test_stats['protocol_errors']}")
            print(f"   命令频率: {rate:.2f} 命令/秒")
            
            if self.test_stats['response_times']:
                response_times = self.test_stats['response_times']
                avg_time = sum(response_times) / len(response_times)
                min_time = min(response_times)
                max_time = max(response_times)
                print(f"   平均响应时间: {avg_time:.1f}ms")
                print(f"   最短响应时间: {min_time:.1f}ms")
                print(f"   最长响应时间: {max_time:.1f}ms")
            
            print(f"\n📋 各功能测试统计:")
            for test_type, stats in self.test_stats['relay_tests'].items():
                if stats['total'] > 0:
                    success_rate_type = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
                    print(f"   {test_type}: 总计{stats['total']} 成功{stats['success']}({success_rate_type:.1f}%) 失败{stats['failed']} 超时{stats['timeout']}")
            
            print("=" * 80)

def show_menu():
    """显示主菜单"""
    print("\n" + "="*80)
    print("🎮 ESP32控制盒综合测试菜单")
    print("="*80)
    print("继电器控制:")
    print("  1.  读取继电器状态")
    print("  2.  打开指定继电器")
    print("  3.  关闭指定继电器")
    print("  4.  打开所有继电器")
    print("  5.  关闭所有继电器")
    print("  6.  继电器延时测试")
    print("")
    print("日志和统计:")
    print("  7.  获取设备统计信息")
    print("  8.  获取设备日志")
    print("  9.  清空设备日志")
    print("  10. 重置统计信息")
    print("  11. 重置重启次数")
    print("")
    print("系统功能:")
    print("  12. 重启设备")
    print("  13. 设备信息总览")
    print("")
    print("自动化测试:")
    print("  14. 自动化继电器测试")
    print("  15. 压力测试")
    print("")
    print("其他:")
    print("  16. 显示测试统计")
    print("  0.  退出程序")
    print("-"*80)

def run_automated_relay_test(tester):
    """运行自动化继电器测试"""
    print(f"\n🚀 开始自动化继电器测试...")
    
    test_sequence = [
        ("读取初始状态", lambda: tester.read_relay_status()),
        ("测试单个继电器控制", lambda: test_individual_relays(tester)),
        ("测试全部继电器控制", lambda: test_all_relays(tester)),
        ("测试延时功能", lambda: test_delay_functions(tester)),
        ("读取最终状态", lambda: tester.read_relay_status()),
    ]
    
    for test_name, test_func in test_sequence:
        print(f"\n📋 {test_name}")
        print("-" * 60)
        test_func()
        time.sleep(2)
    
    print(f"\n✅ 自动化继电器测试完成!")

def test_individual_relays(tester):
    """测试单个继电器控制"""
    test_relays = [1, 3, 5, 7, 9, 11, 13]  # 测试奇数编号继电器
    
    for relay in test_relays:
        print(f"\n🔧 测试继电器{relay}")
        tester.open_relay(relay)
        time.sleep(1)
        tester.read_relay_status()
        time.sleep(1)
        tester.close_relay(relay)
        time.sleep(1)

def test_all_relays(tester):
    """测试全部继电器控制"""
    print(f"\n🔧 测试全部继电器控制")
    tester.open_all_relays()
    time.sleep(2)
    tester.read_relay_status()
    time.sleep(2)
    tester.close_all_relays()
    time.sleep(2)
    tester.read_relay_status()

def test_delay_functions(tester):
    """测试延时功能"""
    print(f"\n🔧 测试延时功能")
    tester.relay_open_delay(1, 3000)  # 继电器1打开3秒后关闭
    time.sleep(1)
    tester.relay_close_delay(2, 2000)  # 继电器2关闭2秒后打开
    time.sleep(4)  # 等待延时完成

def run_stress_test(tester):
    """运行压力测试"""
    print(f"\n🚀 开始压力测试... (按Ctrl+C停止)")
    
    tester.test_stats['start_time'] = datetime.now()
    
    test_cases = [
        ("读取状态", lambda: tester.read_relay_status()),
        ("随机继电器开启", lambda: tester.open_relay(random.randint(1, 14))),
        ("随机继电器关闭", lambda: tester.close_relay(random.randint(1, 14))),
        ("全部开启", lambda: tester.open_all_relays()),
        ("全部关闭", lambda: tester.close_all_relays()),
    ]
    
    cycle_count = 0
    
    try:
        while True:
            cycle_count += 1
            print(f"\n🔄 压力测试周期 #{cycle_count}")
            
            # 随机选择测试用例
            test_name, test_func = random.choice(test_cases)
            test_func()
            
            # 每10个周期显示统计
            if cycle_count % 10 == 0:
                tester.print_test_statistics()
            
            time.sleep(random.uniform(0.5, 1.5))
            
    except KeyboardInterrupt:
        print(f"\n\n⛔ 压力测试停止")
    
    tester.print_test_statistics()

def show_device_overview(tester):
    """显示设备信息总览"""
    print(f"\n" + "="*80)
    print(f"📊 设备信息总览 (完整版)")
    print("="*80)
    
    # 获取最新统计信息
    tester.get_device_stats()
    time.sleep(2)
    
    if tester.device_stats:
        stats = tester.device_stats
        
        # 显示所有原始数据
        print(f"🔍 完整统计数据:")
        print("-" * 70)
        for key, value in stats.items():
            if isinstance(value, dict):
                print(f"   {key}:")
                for sub_key, sub_value in value.items():
                    print(f"     {sub_key}: {sub_value}")
            elif isinstance(value, list):
                print(f"   {key}: {value}")
            else:
                print(f"   {key}: {value}")
        print("-" * 70)
        
        print(f"🎯 基本信息:")
        print(f"   设备ID: {stats.get('device_id', 'N/A')}")
        print(f"   固件版本: {stats.get('Version', 'N/A')}")
        print(f"   设备编号: {stats.get('device_5id', 'N/A')}")
        print(f"   运行时间: {stats.get('uptime_seconds', 0)}秒 ({stats.get('uptime_seconds', 0)//3600}小时 {(stats.get('uptime_seconds', 0)%3600)//60}分钟)")
        print(f"   启动时间戳: {stats.get('boot_timestamp', 'N/A')}")
        
        print(f"\n💾 内存信息:")
        if 'free_heap' in stats:
            free_heap = stats['free_heap']
            print(f"   当前空闲堆内存: {free_heap:,} 字节 ({free_heap/1024:.2f} KB)")
        if 'min_free_heap' in stats:
            min_heap = stats['min_free_heap']
            print(f"   历史最小空闲堆: {min_heap:,} 字节 ({min_heap/1024:.2f} KB)")
        if 'total_heap' in stats:
            total_heap = stats['total_heap']
            print(f"   总堆内存: {total_heap:,} 字节 ({total_heap/1024:.2f} KB)")
            if 'free_heap' in stats:
                used_heap = total_heap - stats['free_heap']
                usage_percent = (used_heap / total_heap) * 100
                print(f"   已用堆内存: {used_heap:,} 字节 ({usage_percent:.1f}%)")
        
        # 显示所有可能的内存字段
        memory_fields = ['largest_free_block', 'heap_size', 'free_internal_heap', 'free_spiram']
        for field in memory_fields:
            if field in stats:
                print(f"   {field}: {stats[field]:,} 字节")
        
        print(f"\n🔄 重启信息:")
        print(f"   重启次数: {stats.get('reboot_count', 0)}")
        print(f"   重启原因: {stats.get('last_reset_reason', 'N/A')}")
        print(f"   上次重启时间: {stats.get('last_reboot_time', 'N/A')}")
        
        print(f"\n📊 运行统计:")
        # 显示所有可能的统计字段
        stat_fields = ['nvs_writes', 'ota_attempts', 'task_count', 'queue_size', 'cpu_frequency', 
                      'flash_size', 'flash_speed', 'chip_revision', 'sdk_version']
        for field in stat_fields:
            if field in stats:
                print(f"   {field}: {stats[field]}")
        
        print(f"\n⚠️  完整错误统计:")
        # 显示所有可能的错误字段
        all_error_fields = ['wifi_errors', 'mqtt_errors', 'relay_errors', 'system_warnings', 
                           'ota_errors', 'nvs_errors', 'task_errors', 'memory_errors', 
                           'network_errors', 'sensor_errors', 'io_errors', 'timer_errors']
        total_errors = 0
        for error_field in all_error_fields:
            if error_field in stats:
                error_count = stats[error_field]
                total_errors += error_count
                status = "⚠️ " if error_count > 0 else "✅"
                print(f"   {status} {error_field}: {error_count}")
        
        print(f"   📈 总错误数: {total_errors}")
        
        print(f"\n📋 日志缓冲区:")
        print(f"   当前日志: {stats.get('log_buffer_count', 0)}条")
        print(f"   缓冲区大小: {stats.get('log_buffer_size', 0)}条")
        buffer_usage = 0
        if stats.get('log_buffer_size', 0) > 0:
            buffer_usage = (stats.get('log_buffer_count', 0) / stats.get('log_buffer_size', 0)) * 100
        print(f"   缓冲区使用率: {buffer_usage:.1f}%")
        
        # WiFi信息完整显示
        wifi_info = stats.get('wifi_info', {})
        if wifi_info:
            print(f"\n📡 WiFi信息:")
            for wifi_key, wifi_value in wifi_info.items():
                if isinstance(wifi_value, list):
                    print(f"   {wifi_key}: {wifi_value}")
                else:
                    print(f"   {wifi_key}: {wifi_value}")
        
        # 网络统计
        network_fields = ['packets_sent', 'packets_received', 'bytes_sent', 'bytes_received', 
                         'connection_count', 'disconnection_count']
        network_stats = {}
        for field in network_fields:
            if field in stats:
                network_stats[field] = stats[field]
        
        if network_stats:
            print(f"\n🌐 网络统计:")
            for field, value in network_stats.items():
                print(f"   {field}: {value}")
        
        # 任务信息
        task_fields = ['active_tasks', 'pending_tasks', 'completed_tasks', 'failed_tasks']
        task_stats = {}
        for field in task_fields:
            if field in stats:
                task_stats[field] = stats[field]
        
        if task_stats:
            print(f"\n⚙️  任务统计:")
            for field, value in task_stats.items():
                print(f"   {field}: {value}")
    
    # 显示继电器状态
    print(f"\n🔗 继电器状态详情:")
    high_byte = tester.device_relay_status['high']
    low_byte = tester.device_relay_status['low']
    
    print(f"   原始状态: 高字节=0x{high_byte:02X}({high_byte:08b}) 低字节=0x{low_byte:02X}({low_byte:08b})")
    
    relay_states = []
    for i in range(14, 8, -1):
        if i <= 14:
            state = "ON " if (high_byte & (1 << (i-9))) else "OFF"
            relay_states.append(f"R{i:2d}:{state}")
    for i in range(8, 0, -1):
        state = "ON " if (low_byte & (1 << (i-1))) else "OFF"
        relay_states.append(f"R{i:2d}:{state}")
    
    # 按行显示继电器状态
    print(f"   继电器状态:")
    for i in range(0, len(relay_states), 7):
        line_states = relay_states[i:i+7]
        print(f"     {' '.join(line_states)}")
    
    # 统计继电器开启数量
    on_count = sum(1 for state in relay_states if "ON" in state)
    off_count = len(relay_states) - on_count
    print(f"   状态汇总: 开启 {on_count}个, 关闭 {off_count}个")
    
    print("="*80)

def signal_handler(signum, frame):
    """信号处理器"""
    print(f"\n⛔ 收到信号 {signum}，正在退出...")
    sys.exit(0)

def main():
    """主函数"""
    # 注册信号处理器
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    print("🎯 ESP32控制盒综合测试程序")
    print("📝 请输入设备参数 (直接按Enter使用默认值)")
    
    # 获取用户输入
    broker = input("MQTT服务器地址 [mqtt.hhwl.lhb.ink]: ").strip() or "mqtt.hhwl.lhb.ink"
    port_str = input("MQTT端口 [1883]: ").strip() or "1883"
    username = input("MQTT用户名 [xxxxxxxxxxxx]: ").strip() or "xxxxxxxxxxxx"
    password = input("MQTT密码 [controlv2]: ").strip() or "controlv2"
    mac = input("设备MAC地址 [3c8a1fd51e48]: ").strip() or "3c8a1fd51e48"
    
    try:
        port = int(port_str)
    except ValueError:
        print("❌ 端口号无效，使用默认值1883")
        port = 1883
    
    # 创建测试器
    tester = ControlBoxTester(broker, port, username, password, mac)
    
    # 连接MQTT服务器
    if not tester.connect():
        print("❌ 无法连接MQTT服务器，程序退出")
        return
    
    try:
        while True:
            show_menu()
            choice = input("请选择操作 (0-16): ").strip()
            
            if choice == "0":
                break
            elif choice == "1":
                tester.read_relay_status()
            elif choice == "2":
                relay_num = int(input("请输入继电器编号 (1-14): "))
                tester.open_relay(relay_num)
            elif choice == "3":
                relay_num = int(input("请输入继电器编号 (1-14): "))
                tester.close_relay(relay_num)
            elif choice == "4":
                tester.open_all_relays()
            elif choice == "5":
                tester.close_all_relays()
            elif choice == "6":
                relay_num = int(input("请输入继电器编号 (1-14): "))
                delay_ms = int(input("请输入延时时间 (毫秒): "))
                action = input("选择动作 (1=开启延时关闭, 2=关闭延时开启): ")
                if action == "1":
                    tester.relay_open_delay(relay_num, delay_ms)
                elif action == "2":
                    tester.relay_close_delay(relay_num, delay_ms)
            elif choice == "7":
                tester.get_device_stats()
            elif choice == "8":
                count = int(input("请输入日志条数 [50]: ") or "50")
                tester.get_device_logs(count)
            elif choice == "9":
                tester.clear_device_logs()
            elif choice == "10":
                tester.reset_device_stats()
            elif choice == "11":
                tester.reset_reboot_count()
            elif choice == "12":
                confirm = input("⚠️  确认要重启设备吗? (y/N): ")
                if confirm.lower() == 'y':
                    tester.restart_device()
            elif choice == "13":
                show_device_overview(tester)
            elif choice == "14":
                run_automated_relay_test(tester)
            elif choice == "15":
                run_stress_test(tester)
            elif choice == "16":
                tester.print_test_statistics()
            else:
                print("❌ 无效选择")
                
    except KeyboardInterrupt:
        print("\n\n⛔ 用户中断程序")
    except Exception as e:
        print(f"\n❌ 程序异常: {e}")
        import traceback
        traceback.print_exc()
    finally:
        tester.disconnect()
        print("👋 程序结束")

if __name__ == "__main__":
    main() 